package com.atguigu.service.impl;

import com.atguigu.constant.RedisConst;
import com.atguigu.entity.PrepareSeckillOrder;
import com.atguigu.entity.SeckillProduct;
import com.atguigu.entity.UserSeckillSkuInfo;
import com.atguigu.mapper.SeckillProductMapper;
import com.atguigu.result.RetVal;
import com.atguigu.result.RetValCodeEnum;
import com.atguigu.service.SeckillProductService;
import com.atguigu.util.MD5;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhangqiang
 * @since 2021-09-13
 */
@Service
public class SeckillProductServiceImpl extends ServiceImpl<SeckillProductMapper, SeckillProduct> implements SeckillProductService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void propareSeckil(UserSeckillSkuInfo userSeckillSkuInfo) {
        //判断商品是否卖完
        String userId = userSeckillSkuInfo.getUserId();
        Long skuId = userSeckillSkuInfo.getSkuId();
        String state = (String)redisTemplate.opsForValue().get(RedisConst.SECKILL_STATE_PREFIX+skuId);
        //商品已经卖完
        if (!RedisConst.CAN_SECKILL.equals(state)){
            return;
        }
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisConst.PREPARE_SECKILL_USERID_SKUID + userId, skuId,RedisConst.PREPARE_SECKILL_LOCK_TIME, TimeUnit.SECONDS);
        if (!flag){
            return;
        }
        //从仓库中减库存,从list集合中弹出一个
        String stockSkuId=(String)redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX+skuId).rightPop();
        if (StringUtils.isEmpty(stockSkuId)){
            //通知其他节点该商品不可秒杀
            redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL, skuId+":"+RedisConst.CAN_NOT_SECKILL);
            return;
        }
        //用户抢购的预下单商品信息存储到redis
        PrepareSeckillOrder prepareSeckillOrder = new PrepareSeckillOrder();
        prepareSeckillOrder.setUserId(userId);
        prepareSeckillOrder.setBuyNum(1);
        SeckillProduct seckillProduct = getSeckillProductFromRedis(skuId);
        prepareSeckillOrder.setSeckillProduct(seckillProduct);
                //设置订单码
        prepareSeckillOrder.setPrepareOrderCode(MD5.encrypt(userId+skuId));
        redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).put(userId, prepareSeckillOrder);
        updateSeckillStock(skuId);
    }

    @Override
    public SeckillProduct getSeckillProductFromRedis(Long skuId) {
        return (SeckillProduct) redisTemplate.opsForHash().get(RedisConst.SECKILL_PRODUCT, skuId.toString());
    }

    private void updateSeckillStock(Long skuId){
        Long stockCount = redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).size();
        if (stockCount%2==0){
            SeckillProduct seckillProduct = getSeckillProductFromRedis(skuId);
            seckillProduct.setStockCount(stockCount.intValue());
            baseMapper.updateById(seckillProduct);
            //更新redis缓存 为了给用户看 有没有机会秒到
            redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(skuId, seckillProduct);
        }
    }

    public RetVal hasQualified(Long skuId,String userId){
        //如果预下单中有用户的信息,说明用户有抢购资格
        Boolean isExist = redisTemplate.hasKey(RedisConst.PREPARE_SECKILL_USERID_SKUID + userId);
        if (isExist){
           PrepareSeckillOrder prepareSeckillOrder=(PrepareSeckillOrder) redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).get(userId);
           if (prepareSeckillOrder!=null){
               return  RetVal.build(prepareSeckillOrder, RetValCodeEnum.PREPARE_SECKILL_SUCCESS);
           }
        }
        //如果用户秒杀了同一件商品
        Integer orderId = (Integer)redisTemplate.boundHashOps(RedisConst.BOUGHT_SECKILL_USER_ORDER).get(userId);
        if (orderId!=null){
            return RetVal.build(null, RetValCodeEnum.SECKILL_ORDER_SUCCESS);
        }
        return RetVal.build(null, RetValCodeEnum.SECKILL_RUN);
    }
}










